home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Kit PC World De Ampliacion De Windows 95
/
Kit PC World de ampliacion de Windows 95.iso
/
internet
/
sweeper
/
samples
/
asyncstg
/
bytearr.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-05
|
18KB
|
790 lines
#include "barrobj.h"
#include <windows.h>
#include "connect.h"
CAsyncByteArray::CAsyncByteArray()
{
m_dwRefCount=0;
m_punkInner=NULL;
m_punkOuter=NULL;
m_bTerminated=FALSE;
m_bBlocking=TRUE;
InitializeCriticalSection(&m_sectNewReadAllowed);
m_nReadsPending=0;
m_hevntNoReadsPending=NULL;
m_hevntNewFillInfo=NULL;
m_nFillAlloc=0;
m_nFillInfo=0;
m_pFillInfo=NULL;
m_ulFillSize=0;
InitializeCriticalSection(&m_sectLBConnect);
m_pCacheArray=NULL;
m_pDataArray=NULL;
m_pLBConnect=NULL;
}
HRESULT CAsyncByteArray::Initialize(IUnknown* punkOuter) {
try
{
m_punkInner=new CInnerUnk(this);
}
catch(...)
{
m_punkInner=NULL;
return E_OUTOFMEMORY;
}
if (punkOuter)
{
m_punkOuter=punkOuter;
}
else
{
m_punkOuter=(IUnknown*) m_punkInner;
}
m_hevntNoReadsPending=CreateEvent(NULL, TRUE, TRUE, NULL);
if (!m_hevntNoReadsPending)
{
return E_UNEXPECTED;
}
m_hevntNewFillInfo=CreateEvent(NULL, TRUE, FALSE, NULL);
if (!m_hevntNewFillInfo)
{
CloseHandle(m_hevntNoReadsPending);
m_hevntNoReadsPending=NULL;
return E_UNEXPECTED;
}
m_pFillInfo=(FILLINFO*) GlobalAlloc(GPTR, sizeof(FILLINFO)*FILLINFOINITSIZE);
if (!m_pFillInfo)
{
CloseHandle(m_hevntNoReadsPending);
m_hevntNoReadsPending=NULL;
CloseHandle(m_hevntNewFillInfo);
m_hevntNewFillInfo=NULL;
return E_OUTOFMEMORY;
}
m_nFillAlloc=FILLINFOINITSIZE;
m_nFillInfo=0;
return S_OK;
}
CAsyncByteArray::~CAsyncByteArray()
{
if (m_pFillInfo)
{
WRITEFILLINFOLOCK;
m_nFillInfo=0;
m_nFillAlloc=0;
GlobalFree((HGLOBAL)m_pFillInfo);
m_pFillInfo=NULL;
WRITEFILLINFOUNLOCK;
}
if (m_hevntNewFillInfo)
{
CloseHandle(m_hevntNewFillInfo);
m_hevntNewFillInfo=NULL;
}
if (m_hevntNoReadsPending)
{
CloseHandle(m_hevntNoReadsPending);
m_hevntNoReadsPending=NULL;
}
if (m_pCacheArray)
{
ILockBytes *pLB=m_pCacheArray;
m_pCacheArray=NULL;
pLB->Release();
}
if (m_pDataArray)
{
ILockBytes *pLB=m_pDataArray;
m_pDataArray=NULL;
pLB->Release();
}
if (m_pLBConnect)
{
CoDisconnectObject((IUnknown*) m_pLBConnect, NULL);
if (m_pLBConnect)
{
delete m_pLBConnect;
m_pLBConnect=NULL;
}
}
DeleteCriticalSection(&m_sectLBConnect);
DeleteCriticalSection(&m_sectNewReadAllowed);
if (m_punkInner)
{
delete m_punkInner;
}
}
HRESULT CAsyncByteArray::QueryInterface(REFIID riid, void** ppObject) {
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
return m_punkOuter->QueryInterface(riid, ppObject);
}
ULONG CAsyncByteArray::AddRef()
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
return m_punkOuter->AddRef();
}
ULONG CAsyncByteArray::Release()
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
return m_punkOuter->Release();
}
CAsyncByteArray::CInnerUnk::CInnerUnk(CAsyncByteArray* pObj)
{
m_pObj=pObj;
}
HRESULT CAsyncByteArray::CInnerUnk::QueryInterface(REFIID riid, void** ppObject)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (riid==IID_IUnknown || riid==IID_ILockBytes)
{
*ppObject=(ILockBytes*) m_pObj;
}
else if (riid==IID_IFillLockBytes)
{
*ppObject=(IFillLockBytes*) m_pObj;
}
else if (riid==IID_IConnectionPointContainer)
{
*ppObject=(IConnectionPointContainer*) m_pObj;
}
else
{
return E_NOINTERFACE;
}
m_pObj->AddRef();
return S_OK;
}
ULONG CAsyncByteArray::CInnerUnk::AddRef()
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
InterlockedIncrement((long*) &g_dwRefCount);
InterlockedIncrement((long*) &m_pObj->m_dwRefCount);
return m_pObj->m_dwRefCount;
}
ULONG CAsyncByteArray::CInnerUnk::Release()
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
ULONG dwRefCount=(m_pObj->m_dwRefCount)-1;
InterlockedDecrement((long*) &g_dwRefCount);
if (InterlockedDecrement((long*) &m_pObj->m_dwRefCount)==0)
{
delete m_pObj;
return 0;
}
return dwRefCount;
}
HRESULT CAsyncByteArray::ReadAt(ULARGE_INTEGER ulOffset,void *pv, ULONG cb, ULONG *pcbRead)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
if (pcbRead)
{
*pcbRead=0;
}
DWORD dwIndex=0;
FILLINFO* pFillInfo=NULL;
DWORDLONG ulEnd=ulOffset.QuadPart+cb;
do
{
READFILLINFOLOCK;
while (dwIndex<m_nFillInfo)
{
pFillInfo=m_pFillInfo+dwIndex;
if (ulOffset.QuadPart>=pFillInfo->ulOffset)
{
if (ulEnd<=pFillInfo->ulOffset+pFillInfo->cb)
{
// All data is here
READFILLINFOUNLOCK;
return m_pCacheArray->ReadAt(ulOffset, pv, cb, pcbRead);
}
// Part of the data is here: try to read the rest from the Data Array
DWORD cbAvailable=(DWORD) (pFillInfo->cb-(pFillInfo->ulOffset-ulOffset.QuadPart));
ULARGE_INTEGER ulFirstNonAvailable;
ulFirstNonAvailable.QuadPart=ulOffset.QuadPart+cbAvailable;
// (cast DWORDLONG to DWORD is safe since cbAvailable<=cb per the preceding conditions)
if (m_bBlocking)
{
if (m_pDataArray)
{
DWORD cbDataRead=0;
m_pDataArray->ReadAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cb-cbAvailable, &cbDataRead);
if (cbDataRead>0)
{
FillAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cbDataRead, NULL);
if (cbDataRead==cb-cbAvailable)
{
cbDataRead=0;
HRESULT hRes=m_pCacheArray->ReadAt(ulOffset, pv, cbAvailable, &cbDataRead);
if (cbDataRead==cbAvailable)
{
if (pcbRead)
{
*pcbRead=cb;
}
return hRes;
}
}
}
}
break; // for now we retry everything
// This could be optimized by reading the available part now and obtain just the rest later
}
else
{
READFILLINFOUNLOCK;
// Read from cache
DWORD cbCacheRead=0;
HRESULT hRes=m_pCacheArray->ReadAt(ulOffset, pv, cbAvailable, &cbCacheRead);
if (pcbRead)
{
*pcbRead=cbCacheRead;
}
// Try to read the missing part from the Data Array
if (cbCacheRead==cbAvailable && m_pDataArray)
{
DWORD cbDataRead=0;
hRes=m_pDataArray->ReadAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cb-cbAvailable, &cbDataRead);
if (cbDataRead>0)
{
if (pcbRead)
{
*pcbRead+=cbDataRead;
}
FillAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cbDataRead, NULL);
}
if (cbCacheRead+cbDataRead<cb)
{
hRes= ((m_bTerminated ||
(m_ulFillSize && ulEnd>m_ulFillSize)) ? E_FAIL : ASTG_E_PENDING);
}
}
return hRes;
}
}
dwIndex++; // not this block
};
READFILLINFOUNLOCK;
if (m_bBlocking)
{
if (m_ulFillSize && ulEnd>m_ulFillSize)
{
return E_FAIL;
}
DWORD res=WaitForSingleObject(m_hevntNewFillInfo, INFINITE); // wait until the next call to FillAt/FillAppend/FillSetSize/Terminate
if (WAIT_FAILED==res)
{
return E_UNEXPECTED;
}
if (WAIT_ABANDONED==res)
{
return E_FAIL;
}
}
else
{
if (pcbRead)
{
*pcbRead=0;
}
return (m_bTerminated ? E_FAIL : ASTG_E_PENDING);
}
}
while (!m_bTerminated);
return E_FAIL;
}
HRESULT CAsyncByteArray::WriteAt(ULARGE_INTEGER ulOffset,const void *pv, ULONG cb, ULONG *pcbWritten)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (m_pDataArray)
{
m_pDataArray->WriteAt(ulOffset, pv, cb, pcbWritten);
}
return FillAt(ulOffset, pv, cb, pcbWritten);
}
HRESULT CAsyncByteArray::Flush( void)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (m_pDataArray)
{
m_pDataArray->Flush();
}
if (m_pCacheArray)
{
return m_pCacheArray->Flush();
}
return S_OK;
}
HRESULT CAsyncByteArray::SetSize(ULARGE_INTEGER cb)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (m_pDataArray)
{
m_pDataArray->SetSize(cb);
}
return SetFillSize(cb);
}
HRESULT CAsyncByteArray::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
if (m_pDataArray)
{
m_pDataArray->LockRegion(libOffset, cb, dwLockType);
}
return m_pCacheArray->LockRegion(libOffset, cb, dwLockType);
}
HRESULT CAsyncByteArray::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
if (m_pDataArray)
{
m_pDataArray->UnlockRegion(libOffset, cb, dwLockType);
}
return m_pCacheArray->UnlockRegion(libOffset, cb, dwLockType);
}
HRESULT CAsyncByteArray::Stat(STATSTG *pstatstg, DWORD grfStatFlag) {
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
return m_pCacheArray->Stat(pstatstg, grfStatFlag);
}
// IFillLockBytes methods
HRESULT CAsyncByteArray::SetFillSize(ULARGE_INTEGER cb) {
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
HRESULT hRes=m_pCacheArray->SetSize(cb);
if (FAILED(hRes))
{
return hRes;
}
WRITEFILLINFOLOCK;
m_ulFillSize=cb.QuadPart;
DWORD dwIndex=0;
FILLINFO* pFillInfo=NULL;
while (dwIndex<m_nFillInfo)
{
pFillInfo=m_pFillInfo+dwIndex;
// is this block outside the new size?
if (pFillInfo->ulOffset>=cb.QuadPart)
{
m_nFillInfo=dwIndex; // invalidate it and all the following!
break;
}
// is part of this block outsize the new size?
if (pFillInfo->ulOffset+pFillInfo->cb>cb.QuadPart)
{
pFillInfo->cb=cb.QuadPart-pFillInfo->ulOffset; // truncate it
m_nFillInfo=dwIndex+1; // remove all the following blocks
break;
}
dwIndex++;
}
WRITEFILLINFOUNLOCK;
PulseEvent(m_hevntNewFillInfo);
return hRes;
}
HRESULT CAsyncByteArray::FillAppend(void const *pv, ULONG cb, ULONG *pcbWritten)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
WRITEFILLINFOLOCK; // for now: suboptimal since it disables reading while appending!
DWORDLONG ulEnd;
FILLINFO* pFillInfo=NULL;
if (m_nFillInfo>0)
{
pFillInfo=m_pFillInfo+(m_nFillInfo-1);
ulEnd=pFillInfo->ulOffset+pFillInfo->cb;
}
else
{
ulEnd=0;
}
ULONG cbWritten=0;
HRESULT hRes=m_pCacheArray->WriteAt(*((ULARGE_INTEGER*) &ulEnd), pv, cb, &cbWritten);
if (cbWritten>0 && m_nFillInfo==0)
{
m_pFillInfo->cb=cbWritten;
m_pFillInfo->ulOffset=ulEnd;
m_nFillInfo=1;
pFillInfo=m_pFillInfo;
}
else
{
pFillInfo->cb+=cbWritten;
}
if (pcbWritten)
{
*pcbWritten=cbWritten;
}
if (m_ulFillSize && ulEnd>m_ulFillSize)
{
m_ulFillSize=ulEnd;
}
WRITEFILLINFOUNLOCK;
PulseEvent(m_hevntNewFillInfo);
return hRes;
}
HRESULT CAsyncByteArray::FillAt(ULARGE_INTEGER ulOffset, void const *pv, ULONG cb, ULONG *pcbWritten)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (!m_pCacheArray)
{
return ASTG_E_NOTINITIALIZED;
}
ULONG cbWritten=0;
HRESULT hRes=m_pCacheArray->WriteAt(ulOffset, pv, cb, &cbWritten);
if (pcbWritten)
{
*pcbWritten=cbWritten;
}
DWORD dwIndex=0;
DWORDLONG ulEnd=ulOffset.QuadPart+cbWritten;
BOOL bExtended=FALSE;
FILLINFO* pFillInfo=NULL;
WRITEFILLINFOLOCK;
if (m_ulFillSize && ulEnd>m_ulFillSize)
{
m_ulFillSize=ulEnd;
}
while (dwIndex<m_nFillInfo)
{
pFillInfo=m_pFillInfo+dwIndex;
// 1.- New block is completely before this block: insert new FillInfo
if (ulEnd<pFillInfo->ulOffset)
{
pFillInfo=NULL;
if (m_nFillInfo>=m_nFillAlloc)
{
DWORD nNewFillAlloc=m_nFillAlloc+FILLINFOREALLOCSIZE;
FILLINFO* pTemp=(FILLINFO*) GlobalReAlloc(m_pFillInfo, sizeof(FILLINFO)*nNewFillAlloc, GMEM_ZEROINIT);
if (pTemp)
{
m_pFillInfo=pTemp;
m_nFillInfo=nNewFillAlloc;
}
else
{
WRITEFILLINFOUNLOCK;
return E_OUTOFMEMORY;
}
}
pFillInfo=m_pFillInfo+dwIndex;
memmove((pFillInfo+1), pFillInfo, sizeof(FILLINFO)*(m_nFillInfo-dwIndex));
pFillInfo->ulOffset=ulOffset.QuadPart;
pFillInfo->cb=cbWritten;
m_nFillInfo++;
break;
}
// 2.- New block starts before or with this block:
// change ulOffset/cb and check for merge with following block(s)
if (ulOffset.QuadPart<=pFillInfo->ulOffset)
{
pFillInfo->ulOffset=ulOffset.QuadPart;
if (ulEnd>pFillInfo->ulOffset+pFillInfo->cb)
{
// this block became longer
pFillInfo->cb=ulEnd-pFillInfo->ulOffset;
bExtended=TRUE; // need to check for possible merge wih following block(s)
}
else {
// did not change end of this block: done.
break;
}
}
// 3.- new block starts within this block
// change cb and check for merge with following block(s)
else if (ulOffset.QuadPart<=pFillInfo->ulOffset+pFillInfo->cb)
{
if (ulEnd>pFillInfo->ulOffset+pFillInfo->cb)
{
// this block became longer
pFillInfo->cb=ulEnd-pFillInfo->ulOffset;
bExtended=TRUE; // need to check for possible merge with following block(s)
}
else
{
// did not change end of this block: done.
break;
}
}
if (bExtended)
{
// if the block was extended, check if can be merged with the following block(s)
DWORD dwIndex1=dwIndex+1;
DWORD dwRemoveCount=0; // will remove merge block(s)
while (dwIndex1<m_nFillInfo)
{
if (ulEnd<m_pFillInfo[dwIndex1].ulOffset)
{
// new block ends before this block: no more merges
break;
}
else
{
// merge this block with first modified block
dwRemoveCount++; // flag it for removal
if (m_pFillInfo[dwIndex1].ulOffset+m_pFillInfo[dwIndex1].cb>ulEnd)
{
// this block was bigger than the newly written one:
// adjust first modified block
pFillInfo->cb=m_pFillInfo[dwIndex1].ulOffset+m_pFillInfo[dwIndex1].cb-pFillInfo->ulOffset;
// no more merges since this block did not grow
break;
}
}
dwIndex1++;
}
if (dwRemoveCount)
{
// remove merged blocks
memmove((pFillInfo+1), m_pFillInfo+dwIndex+1+dwRemoveCount, sizeof(FILLINFO)*(m_nFillInfo-dwRemoveCount-dwIndex-1));
m_nFillInfo-=dwRemoveCount;
}
break;
}
dwIndex++;
}
if (dwIndex>=m_nFillInfo)
{
// new block did not affect any of the existing blocks: append
pFillInfo=NULL;
if (m_nFillInfo>=m_nFillAlloc)
{
DWORD nNewFillAlloc=m_nFillAlloc+FILLINFOREALLOCSIZE;
FILLINFO* pTemp=(FILLINFO*) GlobalReAlloc(m_pFillInfo, sizeof(FILLINFO)*nNewFillAlloc, GMEM_ZEROINIT);
if (pTemp)
{
m_pFillInfo=pTemp;
m_nFillInfo=nNewFillAlloc;
}
else
{
WRITEFILLINFOUNLOCK;
return E_OUTOFMEMORY;
}
}
pFillInfo=m_pFillInfo+dwIndex;
pFillInfo->ulOffset=ulOffset.QuadPart;
pFillInfo->cb=cbWritten;
m_nFillInfo++;
}
WRITEFILLINFOUNLOCK;
PulseEvent(m_hevntNewFillInfo);
return hRes;
}
HRESULT CAsyncByteArray::Terminate(DWORD dwStatus)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
m_bTerminated=TRUE;
PulseEvent(m_hevntNewFillInfo);
return S_OK;
}
// IConnectionPointContainer methods
HRESULT CAsyncByteArray::EnumConnectionPoints(LPENUMCONNECTIONPOINTS FAR* ppEnum)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
//ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT CAsyncByteArray::FindConnectionPoint(REFIID iid, LPCONNECTIONPOINT FAR* ppCP)
{
if (IsBadWritePtr(this, sizeof(*this)))
{
return E_POINTER;
}
if (IsBadWritePtr(ppCP, sizeof(*ppCP)))
{
return E_POINTER;
}
if (iid==IID_ILockBytes)
{
if (!m_pLBConnect)
{
try
{
m_pLBConnect=new CLockBytesConnectionPoint(this);
}
catch(...)
{
m_pLBConnect=NULL;
}
}
if (!m_pLBConnect)
{
return E_OUTOFMEMORY;
}
if (FAILED(m_pLBConnect->QueryInterface(IID_IConnectionPoint, (void**) ppCP)))
{
//ASSERT(FALSE);
return E_UNEXPECTED;
}
}
/*
else if (iid==IID_IFillLockBytes)
{
if (!m_pFillLBConnect)
{
try
{
m_pFillLBConnect=new CFillLockBytesConnectionPoint(this);
}
catch(...)
{
m_pFillLBConnect=NULL;
}
}
if (!m_pFillLBConnect)
{
return E_OUTOFMEMORY;
}
if (FAILED(m_pFillLBConnect->QueryInterface(IID_IConnectionPoint, *ppCP)))
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
}
else if (iid==IID_IBindStatusCallBack)
{
if (!m_pBSCConnect)
{
try
{
m_pBSCConnect=new CBSCConnectionPoint(this);
}
catch(...)
{
m_pBSCConnect=NULL;
}
}
if (!m_pBSCConnect)
{
return E_OUTOFMEMORY;
}
if (FAILED(m_pBSCConnect->QueryInterface(IID_IConnectionPoint, *ppCP)))
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
}
*/
else
{
return CONNECT_E_NOCONNECTION;
}
return S_OK;
}